Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spatial remove "null" from controls on read(...). #145

Closed
wants to merge 1 commit into from
Closed

Spatial remove "null" from controls on read(...). #145

wants to merge 1 commit into from

Conversation

davidB
Copy link
Member

@davidB davidB commented Jun 4, 2014

It's possible if the class of the control is not found (may be deleted).

In SDK with this modification, the exception about ClassNotFound is "notify"
but it no longer raise a NPE (on clone()) and the j3o can be open and edited
without the missing Control.

SEVERE [com.jme3.export.binary.BinaryImporter]: Exception
java.lang.ClassNotFoundException: vdrones.NewControl
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at com.jme3.export.SavableClassUtil.fromName(SavableClassUtil.java:195)
[catch] at com.jme3.export.binary.BinaryImporter.readObject(BinaryImporter.java:333)
    at com.jme3.export.binary.BinaryInputCapsule.resolveIDs(BinaryInputCapsule.java:483)
    at com.jme3.export.binary.BinaryInputCapsule.readSavableArray(BinaryInputCapsule.java:471)
    at com.jme3.export.binary.BinaryInputCapsule.readSavableArrayList(BinaryInputCapsule.java:587)
    at com.jme3.scene.Spatial.read(Spatial.java:1333)
    at com.jme3.scene.Node.read(Node.java:608)
    at com.jme3.export.binary.BinaryImporter.readObject(BinaryImporter.java:344)
    at com.jme3.export.binary.BinaryInputCapsule.resolveIDs(BinaryInputCapsule.java:483)
    at com.jme3.export.binary.BinaryInputCapsule.readSavableArray(BinaryInputCapsule.java:471)
    at com.jme3.export.binary.BinaryInputCapsule.readSavableArrayList(BinaryInputCapsule.java:587)
    at com.jme3.scene.Node.read(Node.java:598)
    at com.jme3.export.binary.BinaryImporter.readObject(BinaryImporter.java:344)
    at com.jme3.export.binary.BinaryImporter.load(BinaryImporter.java:242)
    at com.jme3.export.binary.BinaryImporter.load(BinaryImporter.java:125)
    at com.jme3.export.binary.BinaryImporter.load(BinaryImporter.java:109)
    at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:288)
    at com.jme3.asset.DesktopAssetManager.loadModel(DesktopAssetManager.java:374)
    at com.jme3.gde.core.assets.SpatialAssetDataObject.loadAsset(SpatialAssetDataObject.java:94)
    at com.jme3.gde.scenecomposer.OpenSceneComposer$1.run(OpenSceneComposer.java:38)
    at java.lang.Thread.run(Thread.java:745)
SEVERE [org.openide.util.Exceptions]
java.lang.NullPointerException
    at com.jme3.scene.Spatial.clone(Spatial.java:1188)
    at com.jme3.scene.Node.clone(Node.java:564)
    at com.jme3.scene.Node.clone(Node.java:60)
    at com.jme3.scene.Spatial.clone(Spatial.java:1173)
    at com.jme3.scene.Node.clone(Node.java:564)
    at com.jme3.scene.Node.clone(Node.java:60)
    at com.jme3.scene.Spatial.clone(Spatial.java:1218)
    at com.jme3.scene.Spatial.clone(Spatial.java:66)
    at com.jme3.asset.CloneableAssetProcessor.createClone(CloneableAssetProcessor.java:48)
    at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:327)
    at com.jme3.asset.DesktopAssetManager.loadModel(DesktopAssetManager.java:374)
[catch] at com.jme3.gde.core.assets.SpatialAssetDataObject.loadAsset(SpatialAssetDataObject.java:94)
    at com.jme3.gde.scenecomposer.OpenSceneComposer$1.run(OpenSceneComposer.java:38)
    at java.lang.Thread.run(Thread.java:745)

It's possible if the class of the control is not found (may be deleted).

In SDK with this modification, the exception about ClassNotFound is "notify"
but it no longer raise a NPE (on clone()) and the j3o can be open and edited
without the missing Control.
@normen
Copy link
Member

normen commented Jun 4, 2014

Generally a j3o that contains a Control that is not available can be considered broken. A j3o always exists in the context of a certain project, just like a Java class. However, for the purpose of loading a "broken" j3o in the SDK this would of course make sense. For that to work theres more issues than this one though, like UserData and other things. From a quick talk in the core chat, moving this kind of functionality globally to the loader and allowing different behaviors for deployment vs. development in case of missing classes or other references would be the preferred way to go if this problem was to be circumvented.

@davidB
Copy link
Member Author

davidB commented Jun 4, 2014

I first try to limit the change to SDK. but it delegate all the stuff to jme'core (read/write are part of the class). And as you can see in the stackstrace there is not lot hook or info coming from core. I agree about having several kind of loader but it's hard to do, and may be impossible without modification of core.

An other approach I imagine (for this case) was to provide a classloader with a fake class for missing Control (I'm not sur if it's possible to copy/rename a class at runtime).

@davidB
Copy link
Member Author

davidB commented Jun 4, 2014

do you have a better suggestion. I currently experiment custom control, and got corrupted j3o. This fix help me to not loose my work. I also let the first exception so at runtime in game it should failed as expected.

@normen
Copy link
Member

normen commented Jun 4, 2014

Just revert to a point where you had that control file?

@davidB
Copy link
Member Author

davidB commented Jun 5, 2014

No, I can't. I create "Trash" (or experimental) Controls, I didn't plan to commit them. I attach them in SceneExplorer. I though I detach them from SceneExplorer, then I delete the class. between all thoses steps I do some start/stop of the SDK due to work on SDK's fixes. And when I reopen the SceneExplorer failed to load the j3o.

I try to re-create the missing class with Control with the same name and the code from the Control's template. But the loader never find them (may be classloader issue).

not tested : I though the behavior is different for missing class used in UserData, because value of user data can be null. And Spatial.clone will not failed if userData has null value, but it failed (NPE) if there are null control :

class Spatial
...
   public Spatial clone(boolean cloneMaterial) {
      //...
            clone.controls = new SafeArrayList<Control>(Control.class);
            for (int i = 0; i < controls.size(); i++) {
                Control newControl = controls.get(i).cloneForSpatial(clone);
                newControl.setSpatial(clone);
                clone.controls.add(newControl);
            }

            if (userData != null) {
                clone.userData = (HashMap<String, Savable>) userData.clone();
            }
    }

And null value for userData => remove :

class Spatial

    public void setUserData(String key, Object data) {
        if (userData == null) {
            userData = new HashMap<String, Savable>();
        }

        if(data == null){
            userData.remove(key);            
        }else if (data instanceof Savable) {
            userData.put(key, (Savable) data);
        } else {
            userData.put(key, new UserData(UserData.getObjectType(data), data));
        }
    }

    @SuppressWarnings("unchecked")
    public <T> T getUserData(String key) {
        if (userData == null) {
            return null;
        }
...

@normen
Copy link
Member

normen commented Jun 5, 2014

Try building the project once, then it should find the new class.

@davidB
Copy link
Member Author

davidB commented Jun 5, 2014

I did, but sometimes it doesn' fix.

@normen
Copy link
Member

normen commented Jun 5, 2014

"Sometimes"? How many times do you attach Controls that you then delete? If it can't be found its not on the classpath ad you will get the same issue when you actually run the application.

@davidB
Copy link
Member Author

davidB commented Jun 5, 2014

when I detect the problem I did 10+ times to diagnose. As I evaluate how to use Control (as Component like in Entity-Component approach), I change/adjsut the code of control and use Scene's visual tools to test.

@davidB
Copy link
Member Author

davidB commented Jun 5, 2014

FYI, I switch my first implementation form Zay-ES to AppState + Control + UserData after I saw your video, with the hope to use SceneComposer & C° for level design, preview ... In my previous prototype I use svg, drawn in inkscape, to programmatically generate Entities + Component.

Scene Visual Tool are far form my original image, so I try to do small contribution to help. But may be I wrong, and I should back to level define in svg (or blender) + Zay-Es. What is your advice ?

(I can move this last comment to forum, if it's a better place).

@normen
Copy link
Member

normen commented Jun 5, 2014

Yeah, if you want to discuss this topic per se further make a forum thread so everybody can take part. You know the opinion of the team on the change and questions about best practices are really not well placed here.

@empirephoenix
Copy link
Contributor

Sounds like this should be closed, in favor of a later solution, that allows different deployment hints?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants